package com.hydra.base.utils;

import org.apache.commons.lang3.StringUtils;

import java.lang.reflect.Field;
import java.math.BigDecimal;
import java.math.RoundingMode;
import java.sql.Timestamp;
import java.text.DateFormat;
import java.text.ParseException;
import java.text.SimpleDateFormat;
import java.util.*;
import java.util.regex.Matcher;
import java.util.regex.Pattern;

/**
 * 一些格式化的工具类
 */
public class FormatUtil {

    public static Object getValue(Object target, String name) throws NoSuchFieldException, IllegalAccessException {
        Class<?> aClass = target.getClass();
        Field field = aClass.getDeclaredField(name);
        field.setAccessible(true);
        return field.get(target);
    }

    public static Object getValueCatch(Object target, String name) {
        try {
            return FormatUtil.getValue(target, name);
        } catch (Exception e){
            return null;
        }
    }

    public static void setValue(Object target, String name, Object value) throws NoSuchFieldException, IllegalAccessException {
        Class<?> aClass = target.getClass();
        Field field = aClass.getDeclaredField(name);
        setValue(field, target, value);
    }

    public static void setValueCatch(Object target, String name, Object value) {
        try {
            FormatUtil.setValue(target, name, value);
        } catch (Exception ignored){
        }
    }

    public static void setValue(Field field, Object target, Object value) throws IllegalAccessException {
        field.setAccessible(true);
        field.set(target, formatValueByType(value, field.getType()));
    }

    public static Object formatValueByType(Object value, Class<?> type){
        String typeName = type.getSimpleName();
        switch (typeName) {
            case "String":
                return value;
            case "Date":
                return isNullToDate(value, null);
            case "Double":
                return isNullToDoubleZero(value);
            case "Integer":
                return isNullToIntZero(value);
            case "Long":
                return isNullToLongZero(value);
            case "Float":
                return isNullToFloatZero(value);
            case "boolean":
            case "Boolean":
                return isNullToBoolean(value, null);
            case "BigDecimal":
                return isNullToBigDecimalZero(value);
        }
        return value;
    }

    // decimal int
    public static int bigDecimalToInt(BigDecimal decimal) {
        if (isEmpty(decimal)) {
            return -1;
        } else {
            return decimal.intValue();
        }
    }

    public static BigDecimal round(BigDecimal b, int scale){
        return isNullToBigDecimalZero(b).divide(BigDecimal.ONE, scale, BigDecimal.ROUND_HALF_UP);
    }

    // decimal double
    public static double bigDecimalToDouble(BigDecimal decimal) {
        if (isEmpty(decimal)) {
            return -1;
        } else {
            return decimal.doubleValue();
        }
    }

    // is null
    public static String isNullToEmpty(Object object) {
        if (isEmpty(object)) {
            return StringUtils.EMPTY;
        } else {
            return String.valueOf(object);
        }
    }
    // is null
    public static String isNullToString(Object object, String temp) {
        if (isEmpty(object)) {
            return temp;
        } else {
            return String.valueOf(object);
        }
    }
    // is null
    public static Boolean isNullToBoolean(Object object, Boolean temp) {
        if (isEmpty(object)) {
            return temp;
        } else {
            String value = String.valueOf(object);
            if("true".equals(value) || "false".equals(value)){
                return Boolean.valueOf(value);
            }
            return !"0".equals(value);
        }
    }
    // is null
    public static Timestamp isNullToTimestamp(Object object) {
        if (isEmpty(object)) {
            return null;
        } else {
            return (Timestamp)object;
        }
    }

    public static String isNullToDateString(Object object, String format) throws Exception {
        DateFormat df = new SimpleDateFormat(format);
        Date date = isNullToDate(object, 0, format);
        return df.format(date);
    }

    public static String isNullToDateString(Object object, int offset, String format) throws Exception {
        DateFormat df = new SimpleDateFormat(format);
        Date date = isNullToDate(object, offset, format);
        return df.format(date);
    }

    public static Date isNullToDate(Object object, Date temp){
        if (!isEmpty(object)) {
            if(object instanceof String){
                String format = "yyyy-MM-dd hh:mm:ss.SSS";
                String value = String.valueOf(object);
                int length = value.length();
                if(length <= format.length()){
                    format = format.substring(0, length);
                }
                return isNullToDate(value, temp, format);
            }else if(object instanceof Date){
                return (Date)object;
            }
        }
        return temp;
    }

    public static Date isNullToDate(Object object, Date temp, String format) {
        DateFormat df = new SimpleDateFormat(format);
        Date date = temp;
        if (!isEmpty(object)) {
            if(object instanceof Date){
                return (Date)object;
            }
            try {
                date = df.parse(String.valueOf(object));
            }catch (Exception e){
                e.printStackTrace();
            }
        }
        return date;
    }

    public static Date isNullToDate(Object object, int offset, String format) throws Exception {
        Date date = isNullToDate(object, new Date(), format);
        Calendar c = Calendar.getInstance();
        c.setTime(date);
        c.add(Calendar.DAY_OF_YEAR, offset);
        return c.getTime();
    }

    /**
     * 获取两个时间的差值
     */
    public static int getDateDiff(Object obj1, Object obj2, String format) throws Exception {
        Date date1 = isNullToDate(obj1, new Date(), format);
        Date date2 = isNullToDate(obj2, new Date(), format);
        return (int) ((date2.getTime() - date1.getTime()) / (1000*3600*24));
    }


    // is null
    public static long isNullToLongZero(Object object) {
        if (isNotEmpty(object)) {
            return Long.parseLong(String.valueOf(object));
        }
        return 0;
    }

    // is null
    public static Object isEmptyToNull(Object object) {
        if (isEmpty(object)) {
            return null;
        } else {
            return object;
        }
    }

    public static String isEmptyToString(Object object, String temp) {
        if (isEmpty(object)) {
            return temp;
        } else {
            return String.valueOf(object);
        }
    }

    // is null
    public static int notNullToInt(Object object) {
        if (isNotEmpty(object)) {
            return Integer.parseInt(String.valueOf(object));
        }
        return -1;
    }

    // is null
    public static long notNullToLong(Object object) {
        if (isNotEmpty(object)) {
            return Long.parseLong(String.valueOf(object));
        }
        return -1;
    }

    public static boolean notNullToBoolean(Object object) {
        if (isNotEmpty(object)) {
            return Boolean.parseBoolean(String.valueOf(object));
        }
        return false;
    }

    // is null
    public static int isNullToIntZero(Object object) {
        if (isNotEmpty(object)) {
            int index = String.valueOf(object).indexOf(".");
            String val = String.valueOf(object);
            if(index > -1){
                val = String.valueOf(object).substring(0, index);
            }
            return Integer.parseInt(val);
        }
        return 0;
    }
    public static Integer isNullToInt(Object object, Integer temp) {
        if (isNotEmpty(object)) {
            return Integer.parseInt(String.valueOf(object));
        }
        return temp;
    }

    // is null
    public static Object isZeroToEmpty(Object object) {
        if (isNotEmpty(object)) {
            double number = Double.parseDouble(String.valueOf(object));
            if (number == 0) {
                return StringUtils.EMPTY;
            } else {
                return formatScale(number, 2);
            }
        }
        return StringUtils.EMPTY;
    }

    // is null
    public static float isNullToFloatZero(Object object) {
        if (isNotEmpty(object)) {
            return Float.parseFloat(String.valueOf(object));
        }
        return 0;
    }

    // is null
    public static double isNullToDoubleZero(Object object) {
        if (isNotEmpty(object)) {
            return Double.parseDouble(String.valueOf(object));
        }
        return 0;
    }

    public static double notNullToDouble(Object object) {
        if (isNotEmpty(object)) {
            return Double.parseDouble(String.valueOf(object));
        }
        return -1;
    }

    // is null
    public static BigDecimal isNullToBigDecimalZero(Object object) {
        return isNullToBigDecimal(object, BigDecimal.ZERO);
    }
    // is null
    public static BigDecimal isNullToBigDecimal(Object object, BigDecimal temp) {
        if (isNotEmpty(object)) {
            return BigDecimal.valueOf(isNullToDoubleZero(object));
        }
        return temp;
    }

    // 格式为分钱
    public static int dollarToCent(double dollar) {
        if (isNotEmpty(dollar)) {
            return new Double(dollar * 100).intValue();
        }
        return -1;
    }

    public static boolean isNotNull(Object object) {
        return !isEmpty(object);
    }

    public static boolean isNotEmpty(Object object) {
        return !isEmpty(object);
    }

    public static boolean isEmpty(Object object) {
        if (object == null) {
            return true;
        } else {
            String obj = String.valueOf(object).trim();
            if("null".equals(obj)){
                return true;
            }else if("NULL".equals(obj)){
                return true;
            }else return "".equals(obj);
        }
    }

    public static ArrayList<Integer> mapListToArrayList(List<Map<String, Object>> mapList, String key) {
        ArrayList<Integer> arrayList = new ArrayList<>();
        for (Map map : mapList) {
            arrayList.add(bigDecimalToInt((BigDecimal) map.get(key)));
        }
        return arrayList;
    }

    public static ArrayList<Double> mapListToDoubleArrayList(List<Map<String, Object>> mapList, String key) {
        ArrayList<Double> arrayList = new ArrayList<>();
        for (Map map : mapList) {
            arrayList.add(bigDecimalToDouble((BigDecimal) map.get(key)));
        }
        return arrayList;
    }

    public static String listToString(List list) {
        if (list != null && list.size() > 0) {
            StringBuffer sb = new StringBuffer(12);
            String[] keyArry = (String[]) list.toArray();
            for (String obj : keyArry) {
                sb.append(obj);
                sb.append(",");
            }
            return sb.substring(0, sb.length() - 1);
        } else {
            return null;
        }
    }

    //日24点
    public static List formatDayChartData(List list) {
        if (list == null || list.isEmpty()) {
            return null;
        }
        ArrayList<Map> chartList = new ArrayList<Map>(24);
        for (int i = 0; i < 24; i++) {
            chartList.add(new HashMap());
        }
        int size = list.size();
        int varj = 0;
        for (int i = 0; i < size; i++) {
            Map tmap = (Map) list.get(i);
            int hours = notNullToInt(tmap.get("HOURS"));
            for (int j = varj; j < 24; j++) {
                if (hours == j) {
                    chartList.set(i, tmap);
                    varj = j + 1;
                    break;
                }
            }
        }
        return chartList;
    }

    //日8点
    public static List formatHourChartData(List list) {
        if (list == null || list.isEmpty()) {
            return null;
        }
        ArrayList<Map> chartList = new ArrayList<Map>(8);
        for (int i = 0; i < 8; i++) {
            chartList.add(new HashMap());
        }
        int size = list.size();
        int varj = 0;
        for (int i = 0; i < size; i++) {
            Map tmap = (Map) list.get(i);
            int hours = notNullToInt(tmap.get("HOURS"));
            for (int j = varj; j < 24; j++) {
                if (hours == j && j % 3 == 0) {
                    chartList.set(i, tmap);
                    varj = j + 3;
                    break;
                }
            }
        }
        return chartList;
    }

    //月
    public static List<?> formatMonthChartData(List<?> list) {
        if (list == null || list.isEmpty()) {
            return null;
        }
        ArrayList<Object> chartList = new ArrayList<Object>();
        int size = list.size();
        for (int i = 0; i < size; i++) {
            Map tmap = (Map) list.get(i);
            int hours = notNullToInt(tmap.get("DAYS"));
            for (int j = 1; j <= 24; j++) {
                if (hours == j) {
                    chartList.add(tmap);
                    break;
                }
            }
        }
        return chartList;
    }

    //年12点
    public static List<?> formatYearChartData(List<?> list) {
        if (list == null || list.isEmpty()) {
            return null;
        }
        ArrayList<Object> chartList = new ArrayList<Object>(12);
        int size = list.size();
        for (int i = 0; i < size; i++) {
            Map tmap = (Map) list.get(i);
            int hours = notNullToInt(tmap.get("YEARS"));
            for (int j = 1; j <= 24; j++) {
                if (hours == j) {
                    chartList.add(tmap);
                    break;
                }
            }
        }
        return chartList;
    }

    public static int isEmptyList(List<?> list) {
        if (list == null || list.isEmpty()) {
            return 0;
        } else {
            return list.size();
        }
    }

    public static String decodeObj(String obj, String str1, String val1, String str2, String val2, String value) {
        if (isNotNull(obj)) {
            if (obj.equals(str1)) {
                return val1;
            } else if (obj.equals(str2)) {
                return val2;
            } else {
                return value;
            }
        } else {
            return value;
        }
    }

    public static int decodeObj(int obj, int int1, int val1, int int2, int val2, int value) {
        if (isNotNull(obj)) {
            if (obj == int1) {
                return val1;
            } else if (obj == int2) {
                return val2;
            } else {
                return value;
            }
        } else {
            return value;
        }
    }

    public static double formatScale(double doubleVal, int scale) {
        if (isEmpty(scale)) {
            scale = 2;
        }
        return new BigDecimal(doubleVal).setScale(scale, RoundingMode.HALF_UP).doubleValue();
    }

    public static double format2Scale(Object object) {
        if (isNotEmpty(object) && isNumeric(String.valueOf(object))) {
            //return Double.parseDouble(String.format("%.2f", String.valueOf(object)));
            return Double
                    .parseDouble(new BigDecimal(String.valueOf(object)).setScale(2, RoundingMode.HALF_UP).toString());
        }
        return 0;
    }

    //java中用正则表达式判断是否为数字
    public static boolean isNumeric(String str) {
        Pattern pattern = Pattern.compile("^[-+]?[0-9]+(\\.[0-9]+)?$"); // ^[-+]?[0-9]+(\\.[0-9]+)?$ 表示正数、负数、小数均可
        Matcher isNum = pattern.matcher(str);
        return isNum.matches();
    }


    public static String formatZeroBefore(String value, int length) {
        StringBuilder buff = new StringBuilder();
        if (isEmpty(value)) {
            for (int i = 0; i < length; i++) {
                buff.append("0");
            }
        } else {
            int size = length - value.length();
            while (size > 0) {
                buff.append("0");
                size--;
            }
        }
        buff.append(value);
        return buff.toString();
    }

    /**
     * 复制map
     */
    public static Map<String, Object> copyMap(Map<String, Object> map){
        Map<String, Object> result = new HashMap<>();
        for(String key: map.keySet()){
            result.put(key, map.get(key));
        }
        return result;
    }

    public static Date formatStringToDate(String dateStr){
        if(isEmpty(dateStr)){
            return null;
        }
        String dateFormat = null;
        int length = dateStr.length();
        if (length > 10){
            dateFormat = "yyyy-MM-dd HH:mm:ss";
        } else {
            dateFormat = "yyyy-MM-dd";
        }
        SimpleDateFormat format = new SimpleDateFormat(dateFormat);
        Date date = null;
        try {
            date = format.parse(dateStr);
        } catch (ParseException e) {
            e.printStackTrace();
        }
        return date;
    }

    public static String formatDate(Date date){
        return formatDate(date, "yyyy-MM-dd");
    }
    public static String formatDateTime(Date date){
        return formatDate(date, "yyyy-MM-dd HH:mm:ss");
    }
    public static String formatDate(Date date, String format){
        SimpleDateFormat sdf = new SimpleDateFormat(format);
        return sdf.format(date);
    }

}
